#ifndef PINQTASK_H
#define PINQTASK_H

#include <e32base.h>
#include <ES_SOCK.h>
#include <IN_SOCK.h>

#define PINQTASKVER 1
#define PINQTASKPREFVER 2
#define PINQDEFPKTSIZE 64
#define PINQDEFPKTCOUNT 4
#define PINQDEFDELAY    1
#define PINQDEFTIMEOUT  5

class RWriteStream;
class RReadStream;
class CPinQTask : public CActive
	{
public:
	enum TState
		{EStopped,ELookingUp,EOpenning,ESending,ESent,EReceiving,EReceived,EDelay};
	enum TErrorCode
		{ENoError,ETimeout,ESeq};
	class TPacket
		{
	public:
		TPacket*		iNext;
		CPinQTask*		iTask;
		TUint			iTime;//Tenth of sec
		TUint           iSeq;	
		TUint			iReceSeq;
		TErrorCode	    iError;
		};	class MObserver
		{
	public:
		/*
		 virtual void Started()=0;
		 virtual void Finished()=0;
		 virtual void Cancelled()=0;
		 virtual void Sent()=0;
		 */
		virtual void TaskStateChangedL(const CPinQTask& aTask,TState aNewState)=0;
		//virtual void TaskErrorL(const CPinQTask& aTask);
		//virtual void PacketReceivedL(const CPinQTask::TPacket& aPacket)=0;
		//virtual void PacketSentL(const CPinQTask::TPacket& aPacket)=0;
		//virtual void TaskErrorL(CPinQTask& aTask)=0;
		};

	class CPref : public CBase
		{
	public:
		CPref ();
		~CPref ();

		inline TInt Category() const
			{return iCategory;}
		inline TInt Delay() const
			{return iDelay;}
		inline TInt Timeout() const
			{return iTimeout;}
		inline TInt PktSize() const
			{return iPktSize;}
		inline TInt PktCount() const
			{return iPktCount;}
		inline TBool Endless() const
			{return iEndless;}
		inline TBool Loop() const
			{return iLoop;}		
		inline const TDesC& Name() const
			{return iName ? *iName : KNullDesC();}
		inline const TDesC& Note() const
			{return iNote ? *iNote : KNullDesC();}

		inline void SetCategory(TInt aCategory)
			{iCategory = aCategory;}
		inline void SetDelay(TInt aDelay)
			{iDelay=aDelay;}
		inline void SetTimeout(TInt aTimeout)
			{iTimeout=aTimeout;}
		inline void SetPktSize(TInt aPktSize)
			{iPktSize = aPktSize;}
		inline void SetPktCount(TInt aPktCount)
			{iPktCount = aPktCount;}
		inline void SetEndless(TBool aEndless)
			{iEndless = aEndless;}
		inline void SetLoop(TBool aLoop)
			{iLoop = aLoop;}
		inline void SetNameL(const TDesC& aName);
		inline void SetNoteL(const TDesC& aText);

		void ExternalizeL(RWriteStream& aStream) const;
		void InternalizeL(RReadStream& aStream);
		void Reset();
	private:
		TInt iCategory;
		TInt iPktSize;
		TInt iPktCount;
		TInt iDelay;
		TInt iTimeout;
		TInt8 iEndless;
		TInt8 iLoop;
		HBufC* iName;
		HBufC* iNote;
		};
	class CTimeout: public CActive
		{
	public:
		CTimeout(CPinQTask& aTask);
		~CTimeout();
		void ConstructL();
		void Start();
	private:
		//Active Object framework
		virtual void RunL();
		virtual void DoCancel();
		virtual TInt RunError(TInt aError);
	private:
		RTimer iTimer;
		CPinQTask& iTask;
		};
public:
	static CPinQTask* NewL();
	static CPinQTask* NewLC();
	static CPinQTask* NewL(const CPref& aPref);
	static CPinQTask* NewLC(const CPref& aPref);
	~CPinQTask();
	
	inline TUid Uid() const
		{
		return iUid;
		}
	inline TState State() const
		{
		return iState;
		}
	inline TErrorCode Error() const
		{
		return iError;
		}
	inline TInt PacketsCount() const
		{
		return iCount;
		}
	inline TInt FirstSeq() const
		{
		return iCount==0?0:iSeq-(iCount-1);
		}
	inline TInt LastSeq() const
		{
		return iSeq;
		}
	inline TPacket* LastPacket() const
		{
		return iLast;
		}
	inline TPacket* PreviousPacket() const
		{
		return iPrevious;
		}
	inline TPacket* FirstPacket() const
		{
		return iFirst;
		}
	inline CPref& Pref()
		{
		return iPref;
		}
	inline const CPref& Pref() const
		{
		return iPref;
		}
	
	inline void SetUid(TUid aUid)
		{
		iUid=aUid;
		}
	//Serialization
	void ExternalizeL(RWriteStream& aStream) const;
	void InternalizeL(RReadStream& aStream);
	//API
	//	void	SetState(TState aState,MObserver& aObserver); //Issue request
	void Start(MObserver& aObserver);
	inline const TDesC& StateName() const
		{
		return CPinQTask::StateName(iState);
		}
	static const TDesC& StateName(CPinQTask::TState aState);
	//Active Object framework
	virtual void RunL();
	virtual void DoCancel();
	virtual TInt RunError(TInt aError);
	
private:
	CPinQTask();
	void ConstructL();
	void ConstructL(const CPref& pref);
	void ResetInternal();
	void SetState(TState aState);

	void CPinQTask::DeletePackets();
	CPinQTask::TPacket* CPinQTask::AddPacket(TUint aSeq,TUint aTime);
	
	void OnAlarm();
	
	void OpenL();
	void OpenL(TUint32 aAddr);
	void SendTo();
	void RecvFrom();
	void OnSent();
	void OnRecvd();
	void NextPing();

private:
	CPref	iPref;
	TUid	iUid;
	TState	iState;
	MObserver*  iObserver;
	TPacket*	iFirst;
	TPacket*	iLast;
	TPacket*	iPrevious;
	TUint		iCount;//zero-based lenght of list
	
	RSocketServ iSocketServ;
	RSocket		iSocket;
	
	CTimeout	iTimeout;
	RTimer		iTimer;
	
	RHostResolver	iResolver;
	TNameEntry		iNameEntry;
	TNameRecord		iNameRecord;
	TInetAddr		iAddress;
	TUint16			iSeq;// 1-based number of last packet
	TBuf8<64>		iData;
	TBuf8<64>		iReceBuf;
	TTime			iSentTime;
	TBool			iErrorState; //indicates error state
	TErrorCode		iError;  //my own error codes
	TInt            iLeaveCode;  //error code in runError
};
// vim: ts=2:sw=2
#endif
